/* 
 * File:   SerialPorts.cpp
 * Author: multitone
 * 
 * Created on 15 de Abril de 2011, 14:36
 */

#include "SerialPorts.h"

SerialPorts::SerialPorts() {
}

SerialPorts::~SerialPorts() {
    Close();
}

/**
 * Metodo responsavel por abrir a porta 
 * @return 
 */
bool SerialPorts::OpenPort() {

    ShowMessage("Em SetingSerialPort()" + serial_port + " - " + baud_rate, COLOR_BLUE, COLOR_GREEN);

    if (!serial_port.empty() && !baud_rate.empty()) {

        m_port = open(serial_port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);

        if (m_port == -1) {
            ShowMessage("Porta serial em uso!" + serial_port, COLOR_BLUE, COLOR_GREEN);
            return false;
        } else {
            ShowMessage("Porta serial aberta com sucesso!: " + serial_port, COLOR_BLUE, COLOR_GREEN);

            /**
             * Reading Data from the Port
             * Reading data from a port is a little trickier. When you operate the port in raw data mode, 
             * each read(2) system call will return the number of characters that are actually available 
             * in the serial input buffers. If no characters are available, the call will block (wait) 
             * until characters come in, an interval timer expires, or an error occurs. The read function 
             * can be made to return immediately by doing the following:
             * 
             * fcntl(fd, F_SETFL, FNDELAY);
             * 
             * The FNDELAY option causes the read function to return 0 if no characters are available on the port. 
             * To restore normal (blocking) behavior, call fcntl() without the FNDELAY option:
             * 
             * fcntl(fd, F_SETFL, 0);
             * 
             * This is also used after opening a serial port with the O_NDELAY option.
             * @return 
             */

            /**
             * Este formato nao funciona para essa aplicacao.
             * Por isso nao esta sendo usado aqui.
             * @return 
             */
            //fcntl(m_port, F_SETFL, FNDELAY); //Define a flag do descritor de arquivo

            /**
             * Testado e indentificado que usando o formato
             * que fica aguardando er melhor para simular uma
             * central de pager.
             * @return 
             */
            fcntl(m_port, F_SETFL, 0); //Define a flag do descritor de arquivo

            // Program serial port to 9600, 8, 1, no parity
            // Get the current options for the port

            //Salva estado atual da porta para futuro uso
            tcgetattr(m_port, &options_orig);

            //Seta o novo estado da porta que sera usado
            tcgetattr(m_port, &options_atual);

            // Set the baud rate to 9600
            if (baud_rate == "1200") {
                cfsetispeed(&options_atual, B1200);
                cfsetospeed(&options_atual, B1200);
            }
            // Set the baud rate to 2400
            if (baud_rate == "2400") {
                cfsetispeed(&options_atual, B2400);
                cfsetospeed(&options_atual, B2400);
            }

            // Set the baud rate to 9600
            if (baud_rate == "9600") {
                cfsetispeed(&options_atual, B9600);
                cfsetospeed(&options_atual, B9600);
            }

            // Set the baud rate to 9600
            if (baud_rate == "19200") {
                cfsetispeed(&options_atual, B19200);
                cfsetospeed(&options_atual, B19200);
            }

            // Set the baud rate to 38400
            if (baud_rate == "38400") {
                cfsetispeed(&options_atual, B38400);
                cfsetospeed(&options_atual, B38400);
            }

            // Enable the receiver and set local mode
            options_atual.c_cflag |= (CLOCAL | CREAD);

            // Setting parity checking (no parity) 8N1
            options_atual.c_cflag &= ~PARENB; /* no parity */
            options_atual.c_cflag &= ~CSTOPB; /* 1 stop bit */
            options_atual.c_cflag &= ~CSIZE; /* Mask the character size bits */
            options_atual.c_cflag |= CS8; /* Select 8 data bits */

            // Setting raw input
            //options.c_lflag &= ~(IGNBRK | IGNPAR| ECHO | ECHOE | ISIG);
            //options_atual.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //Antes
            //options_atual.c_lflag &= ~(IGNBRK | ICANON | IGNPAR | ISIG); //Novo
            
            options_atual.c_lflag &= ~(IGNBRK | IGNPAR | ISIG);

            // Setting raw output
            options_atual.c_oflag &= ~OPOST;
            //options_atual.c_cc[VMIN] = 0; //Novo
            //options_atual.c_cc[VTIME] = 10; //Novo

            //Set the new options for the port
            tcsetattr(m_port, TCSANOW, &options_atual);

            ShowMessage("Toda Configuracao da porta foi Setada!", COLOR_BLUE, COLOR_PINK);
        }
    } else {
        ShowMessage("Sete o Baud-Rate e o Nome da Porta Serial!", COLOR_BLUE, COLOR_GREEN);
        return false;
    }
    //
    return true;
}

/**
 * Metodo responsavel por verificar se 
 * a porta seria esta aberta, pronta 
 * para uso.
 * @return  true ou false
 */
bool SerialPorts::IsOpen() {
    if (m_port == -1) {
        cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                << FG_BLUE << "Erro: Não e possivel abrir a porta."
                << serial_port << END << endl;
        //
        return false;
    }
    //
    return true;
}

/**
 * Metodo responsavel fechar a porta
 * serial para ser aberta novamente
 */
void SerialPorts::Close() {
    //Fecha ela
    close(m_port); //Fecha a porta 

    //Restaura o estado original da porta
    tcsetattr(m_port, TCSANOW, &options_orig);
}

/**
 * Metodo responsavel pela grava��o na porta serial
 */
bool SerialPorts::WriteChar(char c[]) {
    //Se aberta, entra!
    if (IsOpen()) {
        cout << "Gravando...: " << hex << (int) c << endl;
        //
        if (write(m_port, c, 1) < 0) {
            cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                    << FG_BLUE << "Erro: Não e possivel gravar na porta."
                    << serial_port << END << endl;
            return false;
        }
        //
        dirfl->CreateLogCap(c[1], 'w', 'n');
        // 
        if (c[1] >= 0x20 && c[1] <= 0x7e) {
            cout << FG_BLUE << " <<-- Hex:[" << hex << (int) toupper(c[1]) << "]" << FG_MAGENTA << "\tChar:[" << c[1] << "] " << END << endl;
        } else {
            cout << FG_BLUE << " <<-- Hex:[" << hex << (int) toupper(c[1]) << "]" << FG_MAGENTA << "\tChar:[?]" << END << endl;
        }
    }
    //   printf("Gravando: Hex:(%x) ", str);
    return true;
}

bool SerialPorts::WriteBuffer(char char_buffer[]) {
    //
    const int BUFFER_SIZE = strlen(char_buffer);
    char c;
    //
    //Se aberta, entra!
    if (IsOpen()) {
        //
        cout << "Gravando...: " << endl;
        //
        for (int i = 0; i < strlen(char_buffer); i++) {
            //
            if (char_buffer[i] > 0x20 && char_buffer[i] < 0x7e) {
                cout << FG_BLUE << " -->> " << char_buffer[i] << " : " << hex << (int) toupper(char_buffer[i]) << END << endl;
            } else {
                cout << FG_BLUE << " -->> " << "? : " << hex << (int) toupper(char_buffer[i]) << END << endl;
            }
            //
        }
        //
        if (write(m_port, char_buffer, BUFFER_SIZE) < 0) {
            cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                    << FG_BLUE << "Erro: Não e possivel gravar na porta."
                    << serial_port << END << endl;
            return false;
        }

        for (int i = 0; i < strlen(char_buffer); i++) {
            c = char_buffer[i];
            //
            dirfl->CreateLogCap(c, 'w', 'n');
            // 
            if (c >= 0x20 && c <= 0x7e) {
                cout << FG_BLUE << " <<-- Hex:[" << hex << (int) toupper(c) << "]" << FG_MAGENTA << "\tChar:[" << c << "] " << END << endl;
            } else {
                cout << FG_BLUE << " <<-- Hex:[" << hex << (int) toupper(c) << "]" << FG_MAGENTA << "\tChar:[?]" << END << endl;
            }
        }
    }
    //
    return true;
}

/**
 * Metodo de leitura da porta, retornando um
 * caracter(char) lido
 */
char SerialPorts::ReadChar() {
    char c;
    int result;
    dirfl = new DirFile();

    //Tenta ler da porta serial
    if (IsOpen()) {
        //
        result = read(m_port, &c, 1);
        //
        if (result != 1) {
            cerr << FG_CIANO << "Nada para ler da porta." << END << endl;
        } else {
            //
            if (c >= 0x20 && c <= 0x7e) {
                cout << FG_BLUE << " ->> Hex:[" FG_GREEN << hex << (int) toupper(c) << "]" << "\tChar:[" << c << "] " << END << endl;
            } else {
                cout << FG_BLUE << " ->> Hex:[" FG_GREEN << hex << (int) toupper(c) << "]" << "\tChar:[?]" << END << endl;
            }
            // 
            dirfl->CreateLogCap(c, 'r', 'n');
        }
    }
    return c;
}

/**
 * Metodo responsavel por ler uma array
 * de byte da porta serial.
 * @return 
 */
char * SerialPorts::ReadAllChar() {
    //
    static char buffer[255];
    char c;
    int j = 0;
    int result;

    cout << FG_BLUE << "ReadAllChar(): Procurando dados para ler...!!" << END << endl;

    //Tenta ler da porta serial
    if (IsOpen()) {
        //
        while (1) {
            result = read(m_port, &c, 1);
            //
            if (result != 1) {
                cout << FG_BLUE << " Nada para Ler!!" << END << endl;
                break;
            } else {
                buffer[j++] = c;
            }
        }
        //
        for (j; j < 255; j++) buffer[j] = '\0';
        //

        //
        if (j > 0)
            for (int i = 0; i < strlen(buffer); i++) {
                if (buffer[i] > 0x20 && buffer[i] < 0x7e) {
                    cout << FG_BLUE << " -->> " << buffer[i] << " : " << hex << (int) toupper(buffer[i]) << END << endl;
                } else {
                    cout << FG_BLUE << " -->> " << "? : " << hex << (int) toupper(buffer[i]) << END << endl;
                }
            }

        //
    } else {
        cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                << FG_BLUE << "Erro: Não e possivel abrir a porta."
                << serial_port << END << endl;
    }
    //
    return buffer;
}